راهنمای جامع Solid Router، روتر رسمی سمت کلاینت برای SolidJS، شامل نصب، استفاده، ویژگیهای پیشرفته و بهترین شیوهها برای ساخت برنامههای تکصفحهای یکپارچه.
Solid Router: تسلط بر مسیریابی سمت کلاینت در SolidJS
SolidJS که به خاطر عملکرد استثنایی و سادگیاش شناخته میشود، پایهای فوقالعاده برای ساخت برنامههای وب مدرن فراهم میکند. برای ایجاد تجربیات کاربری واقعاً جذاب و کاربرپسند، یک روتر قدرتمند سمت کلاینت ضروری است. اینجا Solid Router وارد میشود، روتر رسمی و توصیهشده برای SolidJS که برای ادغام یکپارچه با اصول واکنشی این فریمورک طراحی شده است.
این راهنمای جامع به دنیای Solid Router میپردازد و همه چیز را از راهاندازی اولیه تا تکنیکهای پیشرفته برای ساخت برنامههای تکصفحهای (SPA) پیچیده و پویا پوشش میدهد. چه یک توسعهدهنده باتجربه SolidJS باشید و چه تازه شروع کردهاید، این مقاله شما را به دانش و مهارتهای لازم برای تسلط بر مسیریابی سمت کلاینت مجهز میکند.
Solid Router چیست؟
Solid Router یک روتر سبک و پربازده سمت کلاینت است که به طور خاص برای SolidJS طراحی شده است. این روتر از واکنشگرایی (reactivity) SolidJS برای بهروزرسانی کارآمد رابط کاربری بر اساس تغییرات URL مرورگر بهره میبرد. برخلاف روترهای سنتی که به مقایسه DOM مجازی (virtual DOM diffing) متکی هستند، Solid Router مستقیماً DOM را دستکاری میکند که منجر به عملکرد سریعتر و قابل پیشبینیتر میشود.
ویژگیهای کلیدی Solid Router عبارتند از:
- مسیریابی اعلانی (Declarative Routing): مسیرهای خود را با استفاده از یک API ساده و شهودی مبتنی بر JSX تعریف کنید.
- مسیریابی پویا (Dynamic Routing): به راحتی مسیرها را با پارامترها مدیریت کنید، که به شما امکان میدهد برنامههای پویا و دادهمحور ایجاد کنید.
- مسیرهای تودرتو (Nested Routes): برنامه خود را با مسیرهای تودرتو به بخشهای منطقی سازماندهی کنید.
- کامپوننت لینک: با استفاده از کامپوننت
<A>به طور یکپارچه بین مسیرها جابجا شوید، که به طور خودکار بهروزرسانی URL و استایلدهی لینک فعال را مدیریت میکند. - بارگذاری داده (Data Loading): دادهها را به صورت ناهمزمان قبل از رندر یک مسیر بارگذاری کنید تا تجربه کاربری روانی را تضمین کنید.
- ترنزیشنها (Transitions): برای بهبود تجربه کاربری، ترنزیشنهای بصری جذابی بین مسیرها ایجاد کنید.
- مدیریت خطا (Error Handling): خطاها را به شیوهای مناسب مدیریت کرده و صفحات خطای سفارشی نمایش دهید.
- ادغام با History API: به طور یکپارچه با History API مرورگر ادغام میشود و به کاربران اجازه میدهد با استفاده از دکمههای back و forward جابجا شوند.
شروع کار با Solid Router
نصب
برای نصب Solid Router، از مدیر بسته مورد علاقه خود استفاده کنید:
npm install @solidjs/router
yarn add @solidjs/router
pnpm add @solidjs/router
راهاندازی اولیه
هسته اصلی Solid Router حول کامپوننتهای <Router> و <Route> میچرخد. کامپوننت <Router> به عنوان ریشه سیستم مسیریابی برنامه شما عمل میکند، در حالی که کامپوننتهای <Route> نگاشت بین URLها و کامپوننتها را تعریف میکنند.
در اینجا یک مثال اولیه آورده شده است:
import { Router, Route } from '@solidjs/router';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<Router>
<Route path="/"> <Home/> </Route>
<Route path="/about"> <About/> </Route>
</Router>
);
}
export default App;
در این مثال، کامپوننت <Router> کل برنامه را در بر میگیرد. کامپوننتهای <Route> دو مسیر را تعریف میکنند: یکی برای مسیر ریشه ("/") و دیگری برای مسیر "/about". هنگامی که کاربر به هر یک از این مسیرها میرود، کامپوننت مربوطه (Home یا About) رندر میشود.
کامپوننت <A>
برای جابجایی بین مسیرها، از کامپوننت <A> ارائه شده توسط Solid Router استفاده کنید. این کامپوننت شبیه به تگ <a> معمولی HTML است، اما به طور خودکار بهروزرسانی URL را مدیریت کرده و از بارگذاری مجدد کامل صفحه جلوگیری میکند.
import { A } from '@solidjs/router';
function Navigation() {
return (
<nav>
<A href="/">Home</A>
<A href="/about">About</A>
</nav>
);
}
export default Navigation;
هنگامی که کاربر روی یکی از این لینکها کلیک میکند، Solid Router URL مرورگر را بهروز میکند و کامپوننت مربوطه را بدون ایجاد بارگذاری مجدد کامل صفحه رندر میکند.
تکنیکهای پیشرفته مسیریابی
مسیریابی پویا با پارامترهای مسیر
Solid Router از مسیریابی پویا پشتیبانی میکند، که به شما امکان میدهد مسیرهایی با پارامتر ایجاد کنید. این ویژگی برای نمایش محتوا بر اساس یک شناسه (ID) یا اسلاگ (slug) خاص مفید است.
import { Router, Route } from '@solidjs/router';
import UserProfile from './components/UserProfile';
function App() {
return (
<Router>
<Route path="/users/:id"> <UserProfile/> </Route>
</Router>
);
}
export default App;
در این مثال، بخش :id در مسیر یک پارامتر مسیر است. برای دسترسی به مقدار پارامتر id در کامپوننت UserProfile، میتوانید از هوک useParams استفاده کنید:
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
return (
<div>
<h1>User Profile</h1>
{user() ? (
<div>
<p>Name: {user().name}</p>
<p>Email: {user().email}</p>
</div>
) : (<p>Loading...</p>)}
</div>
);
}
async function fetchUser(id: string) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
export default UserProfile;
هوک useParams یک شیء حاوی پارامترهای مسیر را برمیگرداند. در این مورد، params.id حاوی مقدار پارامتر id از URL خواهد بود. سپس هوک createResource برای واکشی دادههای کاربر بر اساس این شناسه استفاده میشود.
مثال بینالمللی: یک پلتفرم تجارت الکترونیک جهانی را تصور کنید. شما میتوانید از مسیریابی پویا برای نمایش جزئیات محصول بر اساس شناسه محصول استفاده کنید: /products/:productId. این به شما امکان میدهد به راحتی URLهای منحصر به فردی برای هر محصول ایجاد کنید، که اشتراکگذاری و بوکمارک کردن آیتمهای خاص را برای کاربران، صرف نظر از موقعیت مکانی آنها، آسانتر میکند.
مسیرهای تودرتو
مسیرهای تودرتو به شما امکان میدهند برنامه خود را به بخشهای منطقی سازماندهی کنید. این ویژگی به ویژه برای برنامههای پیچیده با چندین سطح ناوبری مفید است.
import { Router, Route } from '@solidjs/router';
import Dashboard from './components/Dashboard';
import Profile from './components/Profile';
import Settings from './components/Settings';
function App() {
return (
<Router>
<Route path="/dashboard">
<Dashboard/>
<Route path="/profile"> <Profile/> </Route>
<Route path="/settings"> <Settings/> </Route>
</Route>
</Router>
);
}
export default App;
در این مثال، کامپوننت <Dashboard> به عنوان یک کانتینر برای کامپوننتهای <Profile> و <Settings> عمل میکند. مسیرهای <Profile> و <Settings> درون مسیر <Dashboard> تودرتو شدهاند، به این معنی که آنها فقط زمانی رندر میشوند که کاربر در مسیر "/dashboard" باشد.
برای رندر کردن مسیرهای تودرتو در کامپوننت <Dashboard>، باید از کامپوننت <Outlet> استفاده کنید:
import { Outlet } from '@solidjs/router';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<nav>
<A href="/dashboard/profile">Profile</A>
<A href="/dashboard/settings">Settings</A>
</nav>
<Outlet/>
</div>
);
}
export default Dashboard;
کامپوننت <Outlet> به عنوان یک مکاننما (placeholder) عمل میکند که مسیرهای تودرتو در آنجا رندر میشوند. هنگامی که کاربر به "/dashboard/profile" میرود، کامپوننت <Profile> درون کامپोनنت <Outlet> رندر میشود. به طور مشابه، هنگامی که کاربر به "/dashboard/settings" میرود، کامپوننت <Settings> درون کامپوننت <Outlet> رندر خواهد شد.
بارگذاری داده با createResource
بارگذاری ناهمزمان دادهها قبل از رندر یک مسیر برای ارائه یک تجربه کاربری روان بسیار مهم است. Solid Router به طور یکپارچه با هوک createResource از SolidJS ادغام میشود و بارگذاری داده را بسیار آسان میکند.
ما قبلاً نمونهای از این را در کامپوننت UserProfile دیدیم، اما برای وضوح بیشتر دوباره در اینجا آورده شده است:
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
return (
<div>
<h1>User Profile</h1>
{user() ? (
<div>
<p>Name: {user().name}</p>
<p>Email: {user().email}</p>
</div>
) : (<p>Loading...</p>)}
</div>
);
}
async function fetchUser(id: string) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
export default UserProfile;
هوک createResource دو آرگومان میگیرد: یک سیگنال که بارگذاری داده را فعال میکند و یک تابع که دادهها را واکشی میکند. در این مورد، سیگنال () => params.id است، به این معنی که دادهها هر زمان که پارامتر id تغییر کند، واکشی میشوند. تابع fetchUser دادههای کاربر را از یک API بر اساس شناسه واکشی میکند.
هوک createResource یک آرایه حاوی منبع (دادههای واکشی شده) و یک تابع برای واکشی مجدد دادهها برمیگرداند. منبع یک سیگنال است که دادهها را نگه میدارد. شما میتوانید با فراخوانی سیگنال (user()) به دادهها دسترسی پیدا کنید. اگر دادهها هنوز در حال بارگذاری باشند، سیگنال undefined برمیگرداند. این به شما امکان میدهد تا زمانی که دادهها در حال واکشی هستند، یک نشانگر بارگذاری نمایش دهید.
ترنزیشنها
افزودن ترنزیشن بین مسیرها میتواند به طور قابل توجهی تجربه کاربری را بهبود بخشد. در حالی که Solid Router پشتیبانی داخلی از ترنزیشن ندارد، اما به خوبی با کتابخانههایی مانند solid-transition-group برای دستیابی به ترنزیشنهای روان و بصری جذاب ادغام میشود.
ابتدا، بسته solid-transition-group را نصب کنید:
npm install solid-transition-group
yarn add solid-transition-group
pnpm add solid-transition-group
سپس، مسیرهای خود را با کامپوننت <TransitionGroup> بپوشانید:
import { Router, Route } from '@solidjs/router';
import { TransitionGroup, Transition } from 'solid-transition-group';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<Router>
<TransitionGroup>
<Route path="/">
<Transition name="fade" duration={300}>
<Home/>
</Transition>
</Route>
<Route path="/about">
<Transition name="fade" duration={300}>
<About/>
</Transition>
</Route>
</TransitionGroup>
</Router>
);
}
export default App;
در این مثال، هر مسیر با یک کامپوننت <Transition> پوشانده شده است. پراپ name پیشوند کلاس CSS برای ترنزیشن را مشخص میکند و پراپ duration مدت زمان ترنزیشن را بر حسب میلیثانیه مشخص میکند.
شما باید کلاسهای CSS مربوطه را برای ترنزیشن در فایل استایل خود تعریف کنید:
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms ease-in;
}
.fade-exit {
opacity: 1;
}
.fade-exit-active {
opacity: 0;
transition: opacity 300ms ease-out;
}
این کد CSS یک ترنزیشن ساده fade-in/fade-out را تعریف میکند. هنگامی که یک مسیر وارد میشود، کلاسهای .fade-enter و .fade-enter-active اعمال میشوند که باعث میشود کامپوننت به تدریج ظاهر شود. هنگامی که یک مسیر خارج میشود، کلاسهای .fade-exit و .fade-exit-active اعمال میشوند که باعث میشود کامپوننت به تدریج محو شود.
مدیریت خطا
مدیریت مناسب خطاها برای ارائه یک تجربه کاربری خوب ضروری است. Solid Router مدیریت خطای داخلی ندارد، اما شما میتوانید به راحتی آن را با استفاده از یک مرز خطای سراسری (global error boundary) یا یک کنترلکننده خطای مخصوص مسیر پیادهسازی کنید.
در اینجا نمونهای از یک مرز خطای سراسری آورده شده است:
import { createSignal, Suspense, ErrorBoundary } from 'solid-js';
import { Router, Route } from '@solidjs/router';
import Home from './components/Home';
import About from './components/About';
function App() {
const [error, setError] = createSignal(null);
return (
<ErrorBoundary fallback={<p>Something went wrong: {error()?.message}</p>}>
<Suspense fallback={<p>Loading...</p>}>
<Router>
<Route path="/"> <Home/> </Route>
<Route path="/about"> <About/> </Route>
</Router>
</Suspense>
</ErrorBoundary>
);
}
export default App;
کامپوننت <ErrorBoundary> هر خطایی که در فرزندانش رخ دهد را دریافت میکند. پراپ fallback کامپوننتی را مشخص میکند که هنگام وقوع خطا رندر میشود. در این مورد، یک پاراگراف با پیام خطا رندر میشود.
کامپوننت <Suspense> پرامیسهای در حال انتظار را مدیریت میکند که معمولاً با کامپوننتهای ناهمزمان یا بارگذاری داده استفاده میشود. این کامپوننت پراپ `fallback` را تا زمان حل شدن پرامیسها نمایش میدهد.
برای ایجاد یک خطا، میتوانید یک استثنا (exception) را در یک کامپوننت پرتاب کنید:
function Home() {
throw new Error('Failed to load home page');
return <h1>Home</h1>;
}
export default Home;
هنگامی که این کد اجرا میشود، کامپوننت <ErrorBoundary> خطا را دریافت کرده و کامپوننت fallback را رندر میکند.
ملاحظات بینالمللی: هنگام نمایش پیامهای خطا، بینالمللیسازی (i18n) را در نظر بگیرید. از یک کتابخانه ترجمه برای ارائه پیامهای خطا به زبان ترجیحی کاربر استفاده کنید. به عنوان مثال، اگر کاربری در ژاپن با خطا مواجه شود، باید پیام خطا را به زبان ژاپنی ببیند، نه انگلیسی.
بهترین شیوهها برای استفاده از Solid Router
- مسیرهای خود را سازماندهی کنید: از مسیرهای تودرتو برای سازماندهی برنامه خود به بخشهای منطقی استفاده کنید. این کار نگهداری و پیمایش کد شما را آسانتر میکند.
- از پارامترهای مسیر برای محتوای پویا استفاده کنید: از پارامترهای مسیر برای ایجاد URLهای پویا برای نمایش محتوا بر اساس یک شناسه یا اسلاگ خاص استفاده کنید.
- دادهها را به صورت ناهمزمان بارگذاری کنید: دادهها را قبل از رندر یک مسیر به صورت ناهمزمان بارگذاری کنید تا تجربه کاربری روانی را ارائه دهید.
- بین مسیرها ترنزیشن اضافه کنید: از ترنزیشنها برای بهبود تجربه کاربری و ایجاد حس بهتر در برنامه خود استفاده کنید.
- خطاها را به درستی مدیریت کنید: مدیریت خطا را برای دریافت و نمایش خطاها به روشی کاربرپسند پیادهسازی کنید.
- از نامهای توصیفی برای مسیرها استفاده کنید: نامهایی را برای مسیرها انتخاب کنید که به طور دقیق محتوای مسیر را منعکس کنند. این کار درک ساختار برنامه شما را آسانتر میکند.
- مسیرهای خود را تست کنید: تستهای واحد بنویسید تا اطمینان حاصل کنید که مسیرهای شما به درستی کار میکنند. این به شما کمک میکند تا خطاها را زودتر پیدا کرده و از رگرسیون جلوگیری کنید.
نتیجهگیری
Solid Router یک روتر سمت کلاینت قدرتمند و انعطافپذیر است که به طور یکپارچه با SolidJS ادغام میشود. با تسلط بر ویژگیهای آن و پیروی از بهترین شیوهها، میتوانید برنامههای تکصفحهای پیچیده و پویایی بسازید که تجربه کاربری روان و جذابی را ارائه میدهند. از راهاندازی اولیه تا تکنیکهای پیشرفته مانند مسیریابی پویا، بارگذاری داده و ترنزیشنها، این راهنما دانش و مهارتهای لازم را برای پیمایش با اطمینان در دنیای مسیریابی سمت کلاینت در SolidJS در اختیار شما قرار داده است. از قدرت Solid Router بهره ببرید و پتانسیل کامل برنامههای SolidJS خود را آزاد کنید!
به یاد داشته باشید که برای دریافت بهروزترین اطلاعات و مثالها به مستندات رسمی Solid Router مراجعه کنید: [لینک مستندات Solid Router - جایگزین شود]
به ساختن چیزهای شگفتانگیز با SolidJS ادامه دهید!